import pytest

from gpt_engineer.core.default.disk_memory import DiskMemory


def test_DB_operations(tmp_path):
    # Test initialization
    db = DiskMemory(tmp_path)

    # Test __setitem__
    db["test_key"] = "test_value"

    assert (tmp_path / "test_key").is_file()

    # Test __getitem__
    val = db["test_key"]

    assert val == "test_value"


def test_large_files(tmp_path):
    db = DiskMemory(tmp_path)
    large_content = "a" * (10**6)  # 1MB of tools

    # Test write large files
    db["large_file"] = large_content

    # Test read large files
    assert db["large_file"] == large_content


def test_concurrent_access(tmp_path):
    import threading

    db = DiskMemory(tmp_path)

    num_threads = 10
    num_writes = 1000

    def write_to_db(thread_id):
        for i in range(num_writes):
            key = f"thread{thread_id}_write{i}"
            db[key] = str(i)

    threads = []
    for thread_id in range(num_threads):
        t = threading.Thread(target=write_to_db, args=(thread_id,))
        t.start()
        threads.append(t)

    for t in threads:
        t.join()

    # Verify that all expected tools was written
    for thread_id in range(num_threads):
        for i in range(num_writes):
            key = f"thread{thread_id}_write{i}"
            assert key in db  # using __contains__ now
            assert db[key] == str(i)


def test_error_messages(tmp_path):
    db = DiskMemory(tmp_path)

    # Test error on getting non-existent key
    with pytest.raises(KeyError):
        db["non_existent"]

    with pytest.raises(TypeError) as e:
        db["key"] = ["Invalid", "value"]

    assert str(e.value) == "val must be str"


# Generated by CodiumAI


class TestOnDiskRepository:
    #  can set and get a value for a key
    def test_set_and_get_value(self, tmp_path):
        db = DiskMemory(tmp_path)
        db["test_key"] = "test_value"

        assert (tmp_path / "test_key").is_file()
        val = db["test_key"]

        assert val == "test_value"

    #  can check if a key exists in the database
    def test_key_exists(self, tmp_path):
        db = DiskMemory(tmp_path)
        db["test_key"] = "test_value"

        assert "test_key" in db
        assert "nonexistent_key" not in db

    #  can fetch a default value if a key does not exist
    def test_fetch_default_value(self, tmp_path):
        db = DiskMemory(tmp_path)
        default_val = "default_value"

        assert db.get("nonexistent_key", default_val) == default_val

    #  can delete a file or directory in the database
    def test_delete_file_or_directory(self, tmp_path):
        db = DiskMemory(tmp_path)
        db["test_file"] = "test_content"
        db["test_directory/test_file"] = "test_content"

        del db["test_file"]
        del db["test_directory"]

        assert not (tmp_path / "test_file").exists()
        assert not (tmp_path / "test_directory").exists()

    #  can iterate over all files in the database
    def test_iterate_files(self, tmp_path):
        db = DiskMemory(tmp_path)
        db["file1.txt"] = "content1"
        db["file2.txt"] = "content2"
        db["directory/file3.txt"] = "content3"

        files = list(db)

        assert len(files) == 3
        assert "file1.txt" in files
        assert "file2.txt" in files
        assert "directory/file3.txt" in files

    #  raises a KeyError if a non-existent key is accessed
    def test_key_error(self, tmp_path):
        db = DiskMemory(tmp_path)

        with pytest.raises(KeyError):
            _ = db["nonexistent_key"]

    #  raises a ValueError if a file name attempts to access parent path
    def test_value_error(self, tmp_path):
        db = DiskMemory(tmp_path)

        with pytest.raises(ValueError):
            db["../file.txt"] = "content"

    #  raises a TypeError if a non-string value is set for a key
    def test_type_error(self, tmp_path):
        db = DiskMemory(tmp_path)

        with pytest.raises(TypeError):
            db["test_key"] = 123

    #  can handle large file contents
    def test_large_file_contents(self, tmp_path):
        db = DiskMemory(tmp_path)
        large_content = "a" * (10**6)  # 1MB of tools
        db["large_file"] = large_content

        assert db["large_file"] == large_content
